home *** CD-ROM | disk | FTP | other *** search
/ Internet Surfer: Getting Started / Internet Surfer - Getting Started (Wayzata Technology)(7231)(1995).bin / pc / mac / bonus / peter_le / chat__ / tcp_libr / tcpconne.uni next >
Text File  |  1992-12-10  |  18KB  |  644 lines

  1. unit TCPConnections;
  2.  
  3. { From Peter's PNL Libraries }
  4. { Copyright 1992 Peter N Lewis }
  5. { This source may be used for any non-commercial purposes as long as I get a mention }
  6. { in the About box and Docs of any derivative program.  It may not be used in any commercial }
  7. { application without my permission }
  8.  
  9. interface
  10.  
  11.     uses
  12.         TCPStuff;
  13.  
  14.     const  { Tuning parameters }
  15.         max_connections = 20;
  16.         tooManyConnections = -23099;
  17.         TO_FindAddress = 40 * 60;
  18.         TO_FindName = 40 * 60;
  19.         TO_ActiveOpen = 20 * 60;
  20.         TO_Closing = 20 * 60;
  21.         TO_PassiveOpen = longInt(10) * 365 * 24 * 3600 * 60;  { Ten years should be safe enough right? :-) }
  22.  
  23.     const
  24.         any_connection = 0;    { Pass to GetConnectionEvent }
  25.         no_connection = -1;    { Guaranteed invalid connection }
  26.  
  27.     type
  28.         connectionIndex = longInt;
  29.         connectionEvent = (C_NoEvent, C_Found, C_SearchFailed, C_NameFound, C_NameSearchFailed,{}
  30.             C_Established, C_FailedToOpen, C_Closing, C_Closed, C_CharsAvailable, C_HeartBeat);
  31.         connectionEventRecord = record
  32.                 event: connectionEvent;
  33.                 connection: connectionIndex;
  34.                 tcpc: TCPConnectionPtr;
  35.                 dataptr: ptr;
  36.                 value: longInt;
  37.                 timedout: boolean;
  38.             end;
  39.  
  40.     function InitConnections: OSErr;
  41.     procedure CloseConnections;
  42.     procedure TerminateConnections;
  43.     function CanQuit: boolean;
  44. { After Terminate, keep calling GetConnectionEvent(any_connection,cer) until CanQuit is true, then Finish }
  45.     procedure FinishConnections;
  46.     procedure FinishEverything;  { Or just call FinishEverything }
  47.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  48.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  49.     procedure FindString (hostIP: longInt; var s: str255);
  50.     function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  51.     function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  52.     procedure CloseConnection (cp: connectionIndex);
  53.     procedure AbortConnection (cp: connectionIndex); { Violently close connection }
  54.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  55. { Pass any_connection for any event, otherwise cp specifies the event }
  56.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  57.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  58.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  59.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  60.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  61.     procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks, 0 disables heartbeat }
  62.  
  63. implementation
  64.  
  65.     const
  66.         TCPCMagic = 'TCPC';
  67.         TCPCBadMagic = 'badc';
  68.  
  69.     type
  70.         myHostInfo = record
  71.                 hi: hostInfo;
  72.                 done: signedByte;
  73.             end;
  74.         myHostInfoPtr = ^myHostInfo;
  75.         statusType = (CS_None, CS_Searching, CS_NameSearching, CS_Opening, CS_Established, CS_Closing);
  76.         connectionRecord = record
  77.                 magic: OSType;
  78.                 conmagic: longInt;
  79.                 tcpc: TCPConnectionPtr;
  80.                 laststate: TCPStateType; { DEBUG }
  81.                 status: statusType;
  82.                 cacheFaultReturnP: myHostInfoPtr;
  83.                 closedone: boolean;
  84.                 timeout: longInt;
  85.                 dataptr: ptr;
  86.                 heartbeat: longInt; { Time for next heartbeat }
  87.                 period: longInt; { Ticks per heartbeat }
  88.                 tcpstates: packed array[TCPStateType] of boolean; { DEBUG }
  89.                 constates: packed array[connectionEvent] of boolean; { DEBUG }
  90.             end;
  91.  
  92.     var
  93.         connections: array[1..max_connections] of connectionRecord;
  94.         connectionItem: connectionIndex;
  95.         dnrptr: ptr;
  96.         connectionmagic: longInt;
  97.  
  98.     function ValidConnectionSafe (var cp: connectionIndex): boolean;
  99.         var
  100.             ocp: longInt;
  101.             vc: boolean;
  102.     begin
  103.         vc := false;
  104.         ocp := cp;
  105.         cp := cp mod (max_connections + 1);
  106.         if cp > 0 then
  107.             if connections[cp].magic = TCPCMagic then
  108.                 if connections[cp].conmagic = ocp then
  109.                     vc := true;
  110.         ValidConnectionSafe := vc;
  111.     end;
  112.  
  113.     function ValidConnection (var cp: connectionIndex): boolean;
  114.         var
  115.             vc: boolean;
  116.     begin
  117.         vc := ValidConnectionSafe(cp);
  118.         if not vc then
  119.             DebugStr('Invalid Connection');
  120.         ValidConnection := vc;
  121.     end;
  122.  
  123.     procedure SetDataPtr (cp: connectionIndex; dataptr: univ ptr);
  124.     begin
  125.         if ValidConnection(cp) then
  126.             connections[cp].dataptr := dataptr;
  127.     end;
  128.  
  129.     procedure GetDataPtr (cp: connectionIndex; var dataptr: univ ptr);
  130.     begin
  131.         if ValidConnectionSafe(cp) then
  132.             dataptr := connections[cp].dataptr
  133.         else
  134.             dataptr := nil;
  135.     end;
  136.  
  137.     procedure SetConnectionTimeout (cp: connectionIndex; timeout: longInt);
  138.     begin
  139.         if ValidConnection(cp) then
  140.             connections[cp].timeout := timeout;
  141.     end;
  142.  
  143.     procedure GetConnectionTimeout (cp: connectionIndex; var timeout: longInt);
  144.     begin
  145.         if ValidConnection(cp) then
  146.             timeout := connections[cp].timeout
  147.         else
  148.             timeout := -1;
  149.     end;
  150.  
  151.     procedure SetHeartBeat (cp: connectionIndex; n: longInt); { Send C_HeartBeat every n ticks }
  152.     begin
  153.         if ValidConnection(cp) then begin
  154.             if (n < 1) or (n = maxLongInt) then begin
  155.                 connections[cp].period := maxLongInt;
  156.                 connections[cp].heartbeat := maxLongInt;
  157.             end
  158.             else begin
  159.                 connections[cp].period := n;
  160.                 connections[cp].heartbeat := TickCount + n;
  161.             end;
  162.         end;
  163.     end;
  164.  
  165.     procedure GetConnectionTCPC (cp: connectionIndex; var tcpc: TCPConnectionPtr);
  166.     begin
  167.         if ValidConnectionSafe(cp) then
  168.             tcpc := connections[cp].tcpc
  169.         else
  170.             tcpc := nil;
  171.     end;
  172.  
  173.     function MyTCPState (con: TCPConnectionPtr): TCPStateType;
  174.     begin
  175.         if con = nil then
  176.             MyTCPState := T_Closed
  177.         else
  178.             MyTCPState := TCPState(con);
  179.     end;
  180.  
  181. {$S Init}
  182.     function InitConnections: OSErr;
  183.         var
  184.             oe, ooe: OSErr;
  185.             i: connectionIndex;
  186.     begin
  187.         for i := 1 to max_connections do
  188.             connections[i].magic := TCPCBadMagic;
  189.         connectionmagic := 0;
  190.         connectionItem := 1;
  191.         oe := TCPInit;
  192.         if oe = noErr then begin
  193.             oe := TCPOpenResolver(dnrptr);
  194.             if oe <> noErr then
  195.                 TCPFinish;
  196.         end;
  197.         InitConnections := oe;
  198.     end;
  199.  
  200. {$S Term}
  201.     procedure TerminateConnections;
  202.         var
  203.             i: connectionIndex;
  204.             oe: OSErr;
  205.     begin
  206.         for i := 1 to max_connections do
  207.             with connections[i] do
  208.                 if magic = TCPCMagic then
  209.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  210.                         if TCPState(tcpc) <> T_Closed then
  211.                             oe := TCPAbort(tcpc);
  212.     end;
  213.  
  214. {$S Term}
  215.     procedure CloseConnections;
  216.         var
  217.             i: connectionIndex;
  218.             oe: OSErr;
  219.     begin
  220.         for i := 1 to max_connections do
  221.             with connections[i] do
  222.                 if magic = TCPCMagic then
  223.                     if (status = CS_Established) or (status = CS_Opening) or (status = CS_Closing) then
  224.                         if TCPState(tcpc) <> T_Closed then
  225.                             oe := TCPClose(tcpc, nil);
  226.     end;
  227.  
  228. {$S Term}
  229.     function CanQuit: boolean;
  230.         var
  231.             i: connectionIndex;
  232.     begin
  233.         CanQuit := true;
  234.         for i := 1 to max_connections do
  235.             if connections[i].magic = TCPCMagic then
  236.                 CanQuit := false;
  237.     end;
  238.  
  239. {$S Term}
  240.     procedure FinishConnections;
  241.     begin
  242.         TCPCloseResolver(dnrptr);
  243.         TCPFinish;
  244.     end;
  245.  
  246. {$S Term}
  247.     procedure FinishEverything;
  248.         var
  249.             cer: connectionEventRecord;
  250.             dummy: boolean;
  251.             er: eventrecord;
  252.             oe: OSErr;
  253.     begin
  254.         TerminateConnections;
  255.         while not CanQuit do begin
  256.             if GetConnectionEvent(any_connection, cer) then begin
  257.                 dummy := WaitNextEvent(everyEvent, er, 0, nil);
  258.             end
  259.             else
  260.                 dummy := WaitNextEvent(everyEvent, er, 5, nil);
  261.         end;
  262.         FinishConnections;
  263.     end;
  264.  
  265. {$S}
  266.     function CreateConnection (var cp: connectionIndex; dp: ptr): OSErr;
  267.         var
  268.             ts: TCPStateType;
  269.             ce: connectionEvent;
  270.     begin
  271.         connectionmagic := connectionmagic + max_connections + 1;
  272.         cp := 1;
  273.         while (connections[cp].magic = TCPCMagic) and (cp < max_connections) do
  274.             cp := cp + 1;
  275.         with connections[cp] do begin
  276.             if magic = TCPCMagic then
  277.                 CreateConnection := tooManyConnections
  278.             else begin
  279.                 magic := TCPCMagic;
  280.                 conmagic := cp + connectionmagic;
  281.                 closedone := false;
  282.                 tcpc := nil;
  283.                 status := CS_None;
  284.                 cacheFaultReturnP := nil;
  285.                 timeout := maxlongInt;
  286.                 dataptr := dp;
  287.                 period := maxLongInt;
  288.                 heartbeat := maxLongInt;
  289.                 CreateConnection := noErr;
  290.                 cp := cp + connectionmagic;
  291.  
  292.                 for ce := C_NoEvent to C_HeartBeat do
  293.                     constates[ce] := false;
  294.                 for ts := T_WaitingForOpen to T_Unknown do
  295.                     tcpstates[ts] := false;
  296.             end;
  297.         end;
  298.     end;
  299.  
  300.     procedure DestroyConnection (var cp: connectionIndex);
  301.     begin
  302.         if ValidConnection(cp) then
  303.             connections[cp].magic := TCPCBadMagic;
  304.         cp := -1;
  305.     end;
  306.  
  307.     function FindAddress (var cp: connectionIndex; hostName: str255; dataptr: univ ptr): OSErr;
  308.         var
  309.             oe: OSErr;
  310.             cpi: connectionIndex;
  311.     begin
  312.         oe := CreateConnection(cp, dataptr);
  313.         if oe = noErr then begin
  314.             cpi := cp;
  315.             if ValidConnection(cpi) then begin
  316.                 with connections[cpi] do begin
  317.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  318.                     if cacheFaultReturnP = nil then
  319.                         oe := memFullErr
  320.                     else begin
  321.                         cacheFaultReturnP^.done := 0;
  322.                         oe := TCPStrToAddr(dnrptr, hostName, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  323.                         if oe = cacheFault then begin
  324.                             timeout := TickCount + TO_FindAddress;
  325.                             oe := noErr;
  326.                         end
  327.                         else begin
  328.                             cacheFaultReturnP^.done := -1;
  329.                             cacheFaultReturnP^.hi.rtnCode := oe;
  330.                         end;
  331.                         status := CS_Searching;
  332.                     end;
  333.                     if oe <> noErr then begin
  334.                         if cacheFaultReturnP <> nil then
  335.                             DisposPtr(ptr(cacheFaultReturnP));
  336.                         DestroyConnection(cp);
  337.                     end;
  338.                 end;
  339.             end;
  340.         end;
  341.         FindAddress := oe;
  342.     end;
  343.  
  344.     procedure FindString (hostIP: longInt; var s: str255);
  345.     begin
  346.         TCPAddrToStr(dnrptr, hostIP, s);
  347.     end;
  348.  
  349.     function FindName (var cp: connectionIndex; hostIP: longInt; dataptr: univ ptr): OSErr;
  350.         var
  351.             oe: OSErr;
  352.             cpi: connectionIndex;
  353.     begin
  354.         oe := CreateConnection(cp, dataptr);
  355.         if oe = noErr then begin
  356.             cpi := cp;
  357.             if ValidConnection(cpi) then begin
  358.                 with connections[cpi] do begin
  359.                     cacheFaultReturnP := myHostInfoPtr(NewPtr(SizeOf(myHostInfo)));
  360.                     if cacheFaultReturnP = nil then
  361.                         oe := memFullErr
  362.                     else begin
  363.                         cacheFaultReturnP^.done := 0;
  364.                         oe := TCPAddrToName(dnrptr, hostIP, cacheFaultReturnP^.hi, cacheFaultReturnP^.done);
  365.                         if oe = cacheFault then begin
  366.                             timeout := TickCount + TO_FindName;
  367.                             oe := noErr;
  368.                         end
  369.                         else begin
  370.                             cacheFaultReturnP^.done := -1;
  371.                             cacheFaultReturnP^.hi.rtnCode := oe;
  372.                         end;
  373.                         status := CS_NameSearching;
  374.                     end;
  375.                     if oe <> noErr then begin
  376.                         if cacheFaultReturnP <> nil then
  377.                             DisposPtr(ptr(cacheFaultReturnP));
  378.                         DestroyConnection(cp);
  379.                     end;
  380.                 end;
  381.             end;
  382.         end;
  383.         FindName := oe;
  384.     end;
  385.  
  386.     function NewPassiveConnection (var cp: connectionIndex; buffersize: longInt; localport: integer; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  387.         var
  388.             oe: OSErr;
  389.             cpi: connectionIndex;
  390.     begin
  391.         oe := CreateConnection(cp, dataptr);
  392.         if oe = noErr then begin
  393.             cpi := cp;
  394.             if ValidConnection(cpi) then
  395.                 with connections[cpi] do begin
  396.                     oe := TCPPassiveOpen(tcpc, buffersize, localPort, remotehost, remoteport, nil);
  397.                     timeout := TickCount + TO_PassiveOpen;
  398.                     status := CS_Opening;
  399.                     if oe <> noErr then
  400.                         DestroyConnection(cp);
  401.                 end;
  402.         end;
  403.         NewPassiveConnection := oe;
  404.     end;
  405.  
  406.     function NewActiveConnection (var cp: connectionIndex; buffersize: longInt; remotehost: longInt; remoteport: integer; dataptr: univ ptr): OSErr;
  407.         var
  408.             oe: OSErr;
  409.             cpi: connectionIndex;
  410.     begin
  411.         oe := CreateConnection(cp, dataptr);
  412.         if oe = noErr then begin
  413.             cpi := cp;
  414.             if ValidConnection(cpi) then
  415.                 with connections[cpi] do begin
  416.                     oe := TCPActiveOpen(tcpc, buffersize, 0, remotehost, remoteport, nil);
  417.                     timeout := TickCount + TO_ActiveOpen;
  418.                     status := CS_Opening;
  419.                     if oe <> noErr then
  420.                         DestroyConnection(cp);
  421.                 end;
  422.         end;
  423.         NewActiveConnection := oe;
  424.     end;
  425.  
  426.     procedure CloseConnection (cp: connectionIndex);
  427.         var
  428.             oe: OSErr;
  429.     begin
  430.         if ValidConnection(cp) then
  431.             with connections[cp] do begin
  432.                 if not closedone then begin
  433.                     if MyTCPState(tcpc) <> T_Closed then begin
  434.                         oe := TCPClose(tcpc, nil);
  435.                     end;
  436.                     closedone := true;
  437.                 end;
  438.                 status := CS_Closing;
  439.                 timeout := TickCount + TO_Closing;
  440.             end;
  441.     end;
  442.  
  443.     procedure AbortConnection (cp: connectionIndex);
  444.         var
  445.             oe: OSErr;
  446.     begin
  447.         if ValidConnection(cp) then
  448.             with connections[cp] do begin
  449.                 if MyTCPState(tcpc) <> T_Closed then
  450.                     oe := TCPAbort(tcpc);
  451.                 status := CS_Closing;
  452.                 timeout := TickCount + TO_Closing;
  453.             end;
  454.     end;
  455.  
  456.     function GetConnectionEvent (cp: connectionIndex; var cer: connectionEventRecord): boolean;
  457.         procedure HandleConnection (cp: connectionIndex);
  458.             var
  459.                 oe: OSErr;
  460.                 dummysp: stringPtr;
  461.                 l: integer;
  462.                 rcp: connectionIndex;
  463.         begin
  464.             with connections[cp] do begin
  465.                 rcp := conmagic;
  466.                 cer.connection := rcp;
  467.                 cer.tcpc := tcpc;
  468.                 cer.dataptr := dataptr;
  469.                 cer.timedout := false;
  470.                 case status of
  471.                     CS_NameSearching: 
  472.                         with cacheFaultReturnP^, hi do begin
  473.                             if done <> 0 then begin
  474.                                 if rtnCode = noErr then begin
  475.                                     cer.event := C_NameFound;
  476.                                     SanitizeHostName(rtnHostName);
  477.                                     stringHandle(cer.value) := NewString(rtnHostName);
  478.                                 end
  479.                                 else begin
  480.                                     cer.event := C_NameSearchFailed;
  481.                                     cer.value := rtnCode;
  482.                                 end
  483.                             end
  484.                             else if TickCount > timeout then begin
  485.                                 cer.event := C_NameSearchFailed;
  486.                                 cer.value := 1;
  487.                                 cer.timedout := true;
  488.                             end;
  489.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  490.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  491.                                     DisposPtr(ptr(cacheFaultReturnP));
  492.                                 cacheFaultReturnP := nil;
  493.                                 DestroyConnection(rcp);
  494.                             end; {if}
  495.                         end; {with}
  496.                     CS_Searching: 
  497.                         with cacheFaultReturnP^, hi do begin
  498.                             if rtnCode = noErr then begin
  499.                                 cer.event := C_Found;
  500.                                 cer.value := addrs[1];
  501.                             end
  502.                             else if done <> 0 then begin
  503.                                 cer.event := C_SearchFailed;
  504.                                 cer.value := rtnCode;
  505.                             end
  506.                             else if TickCount > timeout then begin
  507.                                 cer.event := C_SearchFailed;
  508.                                 cer.value := 1;
  509.                                 cer.timedout := true;
  510.                             end;
  511.                             if cer.event <> C_NoEvent then begin  { Destroy the connection now }
  512.                                 if done <> 0 then  { If we timed out, then we'll just have to abandon this block.  Oh well }
  513.                                     DisposPtr(ptr(cacheFaultReturnP));
  514.                                 cacheFaultReturnP := nil;
  515.                                 DestroyConnection(rcp);
  516.                             end; {if}
  517.                         end; {with}
  518.                     CS_Opening:  begin
  519.                         laststate := MyTCPState(tcpc);
  520.                         tcpstates[laststate] := true;
  521.                         case laststate of
  522.                             T_WaitingForOpen, T_Opening, T_Listening: 
  523.                                 if TickCount > timeout then begin
  524.                                     CloseConnection(rcp);
  525.                                     cer.event := C_FailedToOpen;
  526.                                     cer.timedout := true;
  527.                                 end;
  528.                             T_Established:  begin
  529.                                 cer.event := C_Established;
  530.                                 status := CS_Established;
  531.                                 timeout := maxLongInt;
  532.                             end;
  533.                             T_PleaseClose, T_Closing:  begin
  534.                                 CloseConnection(rcp);
  535.                                 cer.value := 1;
  536.                                 cer.event := C_FailedToOpen;
  537.                                 timeout := TickCount + TO_Closing;
  538.                             end;
  539.                             T_Closed:  begin
  540.                                 status := CS_Closing;
  541.                                 cer.value := 2;
  542.                                 cer.event := C_FailedToOpen;
  543.                                 timeout := TickCount + TO_Closing;
  544.                             end;
  545.                             otherwise
  546.                                 ;
  547.                         end; {case }
  548.                     end;
  549.                     CS_Established:  begin
  550.                         laststate := MyTCPState(tcpc);
  551.                         tcpstates[laststate] := true;
  552.                         case laststate of
  553.                             T_Established:  begin
  554.                                 cer.value := TCPCharsAvailable(tcpc);
  555.                                 if cer.value > 0 then
  556.                                     cer.event := C_CharsAvailable;
  557.                             end;
  558.                             T_PleaseClose, T_Closing:  begin
  559.                                 cer.value := TCPCharsAvailable(tcpc);
  560.                                 if cer.value > 0 then
  561.                                     cer.event := C_CharsAvailable
  562.                                 else begin
  563. {    CloseConnection(rcp);}
  564.                                     status := CS_Closing;
  565.                                     cer.event := C_Closing;
  566.                                     timeout := TickCount + TO_Closing;
  567.                                 end;
  568.                             end;
  569.  
  570.                             T_Closed:  begin
  571.                                 status := CS_Closing;
  572.                                 cer.event := C_Closing;
  573.                                 timeout := TickCount + TO_Closing;
  574.                             end;
  575.                             otherwise
  576.                                 ;
  577.                         end;
  578.                     end;
  579.                     CS_Closing:  begin
  580.                         laststate := MyTCPState(tcpc);
  581.                         tcpstates[laststate] := true;
  582.                         case laststate of
  583.                             T_WaitingForOpen, T_Opening, T_Listening: 
  584.                                 DebugStr('Strange State 2');
  585.                             T_PleaseClose, T_Closing, T_Established:  begin
  586.                                 cer.value := TCPCharsAvailable(tcpc);
  587.                                 if cer.value > 0 then
  588.                                     cer.event := C_CharsAvailable
  589.                                 else if TickCount > timeout then begin
  590.                                     cer.event := C_Closed;
  591.                                     if tcpc <> nil then begin
  592.                                         oe := TCPAbort(tcpc);
  593.                                         oe := TCPRelease(tcpc);
  594.                                     end;
  595.                                     cer.timedout := true;
  596.                                     DestroyConnection(rcp);
  597.                                 end;
  598.                             end;
  599.                             T_Closed:  begin
  600.                                 cer.event := C_Closed;
  601.                                 if tcpc <> nil then
  602.                                     oe := TCPRelease(tcpc);
  603.                                 DestroyConnection(rcp);
  604.                             end;
  605.                             otherwise
  606.                                 ;
  607.                         end;
  608.                     end;
  609.                     otherwise
  610.                         ;
  611.                 end;
  612.  
  613.                 if (cer.event = C_NoEvent) & (TickCount > heartbeat) then begin
  614.                     cer.event := C_HeartBeat;
  615.                     heartbeat := TickCount + period;
  616.                 end;
  617.                 if cer.event <> C_NoEvent then
  618.                     constates[cer.event] := true;
  619.             end;{with}
  620.         end;{HandleConnection}
  621.         var
  622.             oci: connectionIndex;
  623.     begin
  624.         cer.event := C_NoEvent;
  625.         if cp <> any_connection then begin
  626.             if ValidConnection(cp) then
  627.                 HandleConnection(cp);
  628.         end
  629.         else begin
  630.             oci := connectionItem;
  631.             repeat
  632.                 if connections[connectionItem].magic = TCPCMagic then begin
  633.                     HandleConnection(connectionItem);
  634.                 end;{if}
  635.                 if connectionItem = max_connections then
  636.                     connectionItem := 1
  637.                 else
  638.                     connectionItem := connectionItem + 1;
  639.             until (oci = connectionItem) or (cer.event <> C_NoEvent);
  640.         end;{if}
  641.         GetConnectionEvent := cer.event <> C_NoEvent;
  642.     end;{GetConnectionEvent}
  643.  
  644. end.